﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using TV4Home.Server.TVEInteractionLibrary;
using TV4Home.Server.TVEInteractionLibrary.Interfaces;
using TV4Home.WebInterface.UI.Controls;
using TV4Home.WebInterface.UI.Code;

namespace TV4Home.WebInterface.UI
{
    public partial class TVGuide : PageBase
    {
        PagedDataSource dataSource = new PagedDataSource() { AllowPaging = true };

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!this.IsPostBack)
            {
                ViewState.Clear();

                InitializeDefaultValues();
            }

            // if a search term is passed via query string, write it to the ViewState variable so that the view switches to the search results view
            if (!String.IsNullOrEmpty(Request.QueryString["searchTerm"]))
                this.CurrentSearchTerm = Request.QueryString["searchTerm"];
        }

        private void InitializeDefaultValues()
        {
            //set default value for channels per page
            this.ChannelsPerPage = 15;

            // initialize dropdown list for time
            for (int i = 0; i < 24; i++)
                ddlCurrentTime.Items.Add(new DateTime(1, 1, 1, i, 0, 0, 0).ToShortTimeString());
        }

        public override void UpdateUI()
        {
            // set view index (0=all channels, 1=single channel, 2=search results)
            if (!String.IsNullOrEmpty(this.CurrentSearchTerm))
                MultiView1.ActiveViewIndex = 2;
            else
                MultiView1.ActiveViewIndex = this.CurrentChannelDetailsID == 0 ? 0 : 1;

            // update data
            switch (MultiView1.ActiveViewIndex)
            {
                case 0: // all channels
                    LoadAllChannelsView();
                    break;
                case 1: // single channel
                    LoadSingleChannelView();
                    break;
                case 2:
                    LoadSearchResultsView();
                    break;
                default:
                    throw new ArgumentException("Invalid view index.");
            }
        }

        private void LoadAllChannelsView()
        {
            LoadTimes();
            LoadGroups();
            LoadDataBindings();
        }

        private void LoadSingleChannelView()
        {
            LoadChannelName();
            LoadSingleChannelGuide();
            LoadChannelDetails();
        }

        private void LoadSearchResultsView()
        {
            LoadSearchResults();
        }

        protected void SingleChannel_Clicked(object sender, ChannelClickedEventArgs e)
        {
            this.CurrentChannelDetailsID = e.ChannelID;

            UpdateUI();
        }

        protected void lnkBackToGuide_Click(object sender, EventArgs e)
        {
            this.CurrentChannelDetailsID = 0;

            UpdateUI();
        }

        protected void lnkBackToGuideSearchResults_Click(object sender, EventArgs e)
        {
            this.CurrentSearchTerm = "";

            if (!String.IsNullOrEmpty(Request.QueryString["searchTerm"]))
            {
                // when the request included a query string parameter, we have to do a full refresh of the page. 
                // Otherwise it would immediately go to the search results page again.
                Response.Redirect(Page.ResolveUrl("~/TVGuide.aspx"));
            }
            else
            {
                UpdateUI();
            }
        }

        #region All Channels View
        private void LoadDataBindings()
        {
            dataSource.DataSource = WebService.TV4HomeWebService.ServiceInstance.GetChannelsBasic(this.CurrentChannelGroup);
            dataSource.PageSize = this.ChannelsPerPage;

            if (dataSource.PageCount >= this.CurrentPageIndex)
                dataSource.CurrentPageIndex = this.CurrentPageIndex;
            else
                dataSource.CurrentPageIndex = 0;

            this.RepeaterTVGuide.DataSource = dataSource;
            this.RepeaterTVGuide.DataBind();

            EnablePaging();
        }

        private void LoadTimes()
        {
            ddlCurrentTime.SelectedIndex = this.CurrentDateTime.Hour;

            // update Date textbox
            this.HiddenFieldDate.Value = this.CurrentDateTime.Date.ToString("yyyy-MM-dd");
            this.lblDate.Text = this.CurrentDateTime.Date.ToShortDateString();

            UpdateHoursTimeline();
        }

        private void UpdateHoursTimeline()
        {
            // calculate timespans
            TimeSpan oneHour = TimeSpan.FromMinutes(60);

            TimeSpan totalDuration = TimeSpan.FromHours(WebsiteSettings.TVGuideHoursToShow);
            double onePercent = 100.0 / totalDuration.TotalMinutes;

            TimeSpan timeToNextFullHour = this.CurrentDateTime
                                             .AddHours(1)
                                             .AddMinutes(this.CurrentDateTime.Minute * -1)
                                             .AddSeconds(this.CurrentDateTime.Second * -1)
                                             .Subtract(this.CurrentDateTime);

            // delete all child controls from the timeline panel
            this.pnHoursSeperatorPanel.Controls.Clear();

            // add spacing to the next full hour
            Panel pnHoursSeperatorSpacing = new Panel()
                                                {
                                                    CssClass = "TVGuideHoursSeperatorSpacing",
                                                    Width = Unit.Percentage(onePercent * timeToNextFullHour.TotalMinutes * 0.99)
                                                };

            // if there is enough time in the spacing, add the hour label
            if (timeToNextFullHour.TotalMinutes >= 59)
            {
                // add hour label
                pnHoursSeperatorSpacing.Controls.Add(new Label() { Text = "| " + this.CurrentDateTime.AddMinutes(this.CurrentDateTime.Minute * -1).ToShortTimeString() });
            }
            else
            {
                // add some control so that the div is shown
                pnHoursSeperatorSpacing.Controls.Add(new LiteralControl("&nbsp;"));
            }

            // add it to the timeline panel
            this.pnHoursSeperatorPanel.Controls.Add(pnHoursSeperatorSpacing);

            // get the duration left for showing in the timeline
            TimeSpan durationLeft = totalDuration - timeToNextFullHour;

            // loop until the duration left is 0
            while (durationLeft.TotalMinutes > 0)
            {
                Panel pnHour = new Panel() { CssClass = "TVGuideHoursSeperatorHour" };

                // add hour label
                pnHour.Controls.Add(new Label() { Text = "| " + this.CurrentDateTime.Add(totalDuration - durationLeft).ToShortTimeString() });

                // add the hour panel to the timeline panel
                this.pnHoursSeperatorPanel.Controls.Add(pnHour);

                // set the width
                if (durationLeft >= oneHour)
                {
                    pnHour.Width = Unit.Percentage(onePercent * oneHour.TotalMinutes * 0.99);
                    durationLeft = durationLeft.Subtract(oneHour);
                }
                else
                {
                    pnHour.Width = Unit.Percentage(onePercent * durationLeft.TotalMinutes * 0.99);
                    break;
                }
            }
        }

        private void LoadGroups()
        {
            ddlChannelGroups.Items.Clear();

            foreach (WebChannelGroup c in WebService.TV4HomeWebService.ServiceInstance.GetGroups())
            {
                ddlChannelGroups.Items.Add(new ListItem(c.GroupName, c.IdGroup.ToString()));
            }

            ddlChannelGroups.SelectedValue = this.CurrentChannelGroup.ToString();
        }

        protected void imgSearch_Click(object sender, ImageClickEventArgs e)
        {
            this.CurrentSearchTerm = this.txtSearch.Text;

            UpdateUI();
        }

        protected void lnkRefresh_Click(object sender, EventArgs e)
        {
            this.CurrentDateTime = DateTime.Now;

            RefreshData();
        }

        protected void btnNavTimeLeft_Click(object sender, EventArgs e)
        {
            this.CurrentDateTime = this.CurrentDateTime.AddHours(-1);

            RefreshData();
        }

        protected void btnNavTimeRight_Click(object sender, EventArgs e)
        {
            this.CurrentDateTime = this.CurrentDateTime.AddHours(1);

            RefreshData();
        }

        protected void ddlChannelGroups_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.CurrentChannelGroup = Int32.Parse(ddlChannelGroups.SelectedValue);

            RefreshData();
        }

        protected void ddlCurrentTime_SelectedIndexChanged(object sender, EventArgs e)
        {
            DateTime now = this.CurrentDateTime;
            this.CurrentDateTime = new DateTime(now.Year, now.Month, now.Day, ddlCurrentTime.SelectedIndex, 0, 0);

            RefreshData();
        }

        protected void ddlChannelsPerPage_SelectedIndexChanged(object sender, EventArgs e)
        {
            RefreshData();
        }

        protected void RepeaterTVGuide_ItemDataBound(object sender, RepeaterItemEventArgs e)
        {
            TVGuideSingleRowControl ctrl = e.Item.FindControl("tvGuideSingleRow") as TVGuideSingleRowControl;

            ctrl.ChannelID = ((WebChannelBasic)e.Item.DataItem).IdChannel;
            ctrl.StartTime = this.CurrentDateTime;
            ctrl.EndTime = this.CurrentDateTime.AddHours(WebsiteSettings.TVGuideHoursToShow);

            ctrl.LoadData();
        }

        protected void RepeaterPaging_ItemCommand(object source, RepeaterCommandEventArgs e)
        {
            if (e.CommandName.Equals("lnkbtnPaging"))
            {
                CurrentPageIndex = Convert.ToInt32(e.CommandArgument.ToString());
                UpdateUI();
            }
        }

        protected void RepeaterPaging_ItemDataBound(object sender, RepeaterItemEventArgs e)
        {
            //retrieve current page index and assign different BackColor
            if (Convert.ToInt32((e.Item.DataItem as System.Data.DataRowView).Row["PageIndex"]) == CurrentPageIndex)
            {
                LinkButton btn = (e.Item.FindControl("lnkbtnPaging") as LinkButton);

                btn.BackColor = System.Drawing.Color.Aquamarine;
            }

            //hide linkbutton if only one page
            if (dataSource.PageCount == 1)
                (e.Item.FindControl("lnkbtnPaging") as LinkButton).Visible = false;
        }

        private void EnablePaging()
        {
            System.Data.DataTable dt = new System.Data.DataTable();

            dt.Locale = CultureInfo.CurrentCulture;

            dt.Columns.Add("PageIndex");
            dt.Columns.Add("PageText");

            for (int i = 0; i < dataSource.PageCount; i++)
            {
                System.Data.DataRow dr = dt.NewRow();
                dr[0] = i;      // page index
                dr[1] = i + 1;  // text of page index
                dt.Rows.Add(dr);
            }

            this.RepeaterPaging.DataSource = dt;
            this.RepeaterPaging.DataBind();
        }

        private void RefreshData()
        {
            UpdateUI();

            this.RepeaterTVGuide.DataBind();
        }

        protected void HiddenFieldDate_ValueChanged(object sender, EventArgs e)
        {
            DateTime parsedDate;

            // check if date can be parsed and is different than the current date
            if (DateTime.TryParse(this.HiddenFieldDate.Value, out parsedDate) && parsedDate != this.CurrentDateTime.Date)
            {
                this.CurrentDateTime = parsedDate.Add(this.CurrentDateTime.TimeOfDay);

                RefreshData();
            }
        }
        #endregion

        #region Single Channel View
        private void LoadChannelName()
        {
            if (this.CurrentChannelDetailsID == 0)
                return;

            WebChannelBasic ch = WebService.TV4HomeWebService.ServiceInstance.GetChannelBasicById(this.CurrentChannelDetailsID);

            this.lblChannelName.Text = ch.DisplayName;

            // add logo
            this.imgChannelLogo.ImageUrl = Utils.GetChannelLogoPath(ch);

            if (System.IO.File.Exists(MapPath(this.imgChannelLogo.ImageUrl)))
                this.imgChannelLogo.Visible = true;
            else
                this.imgChannelLogo.Visible = false;
        }

        private void LoadSingleChannelGuide()
        {
            this.tvGuideSingleChannel.ChannelID = this.CurrentChannelDetailsID;
            this.tvGuideSingleChannel.Date = this.CurrentDateTime;
            this.tvGuideSingleChannel.LoadData();

            if (this.tvGuideSingleChannel.ProgramsCount > 6)
                this.panelSingleChannelContainer.Height = Unit.Pixel(20 * this.tvGuideSingleChannel.ProgramsCount);

            string watchUrl = String.Format("MediaStreamingWindow.aspx?channelId={0}", this.CurrentChannelDetailsID);
            this.hlWatchChannel.NavigateUrl = watchUrl;
            this.hlWatchChannel.Attributes.Add("onClick", String.Format("javascript:window.open('{0}', '', 'width=600,height=400,resizable=yes'); return false;", watchUrl));
        }

        private void LoadChannelDetails()
        {
            if (this.CurrentChannelDetailsID == 0)
                return;

            WebChannelDetailed ch = WebService.TV4HomeWebService.ServiceInstance.GetChannelDetailedById(this.CurrentChannelDetailsID);

            if (ch.GroupNames != null)
                this.lblSingleChannelGroup.Text = String.Join(", ", ch.GroupNames.ToArray());
            else
                this.lblSingleChannelGroup.Text = (string)GetLocalResourceObject("lblSingleChannelGroup_NoGroup_Text");

            this.lblSingleChannelFTA.Text = Utils.GetYesNoFromBoolean(ch.FreeToAir == 1);
            this.lblSingleChannelTimesWatched.Text = ch.TimesWatched.ToString();
            this.lblSingleChannelTotalTimeWatched.Text = ch.TotalTimeWatched.TimeOfDay.ToPrettyString();
        }
        #endregion

        #region Search Results View
        private void LoadSearchResults()
        {
            List<WebProgramBasic> searchResults = WebService.TV4HomeWebService.ServiceInstance.SearchProgramsBasic(this.CurrentSearchTerm);

            lblSearchResultsQuery.Text = this.CurrentSearchTerm;
            this.lblSearchResultsCount.Text = searchResults.Count.ToString();

            // if user has Windows 7 installed -> display "Connect to search" button
            if (Request.UserAgent != null && Request.UserAgent.Contains("Windows NT 6.1"))
                hlConnectSearchToWin7.Visible = true;

            // TODO: display search results better
            grvSearchResults.DataSource = searchResults;
            grvSearchResults.DataBind();
        }
        #endregion

        #region ViewState Properties
        /// <summary>
        /// Gets or sets the current date and time that is shown in the guide.
        /// </summary>
        /// <value>The current date time.</value>
        public DateTime CurrentDateTime
        {
            get
            {
                if (ViewState["currentDateTime"] == null)
                    ViewState["currentDateTime"] = DateTime.Now;

                return (DateTime)ViewState["currentDateTime"];
            }
            set
            {
                ViewState["currentDateTime"] = value;
            }
        }

        /// <summary>
        /// Gets or sets the index of the current page.
        /// </summary>
        /// <value>The index of the current page.</value>
        int CurrentPageIndex
        {
            get
            {
                if (ViewState["currentPageIndex"] == null)
                    ViewState["currentPageIndex"] = 0;

                return (int)ViewState["currentPageIndex"];
            }
            set
            {
                ViewState["currentPageIndex"] = value;
            }
        }

        /// <summary>
        /// Gets or sets the channels per page.
        /// </summary>
        /// <value>The channels per page.</value>
        int ChannelsPerPage
        {
            get
            {
                return Int32.Parse(this.ddlChannelsPerPage.SelectedValue);
            }
            set
            {
                this.ddlChannelsPerPage.SelectedValue = Convert.ToString(value);
            }
        }

        /// <summary>
        /// Gets or sets the current channel group.
        /// </summary>
        /// <value>The current channel group.</value>
        int CurrentChannelGroup
        {
            get
            {
                if (ViewState["currentChannelGroup"] == null)
                    ViewState["currentChannelGroup"] = WebService.TV4HomeWebService.ServiceInstance.GetGroups().First().IdGroup;

                return (int)ViewState["currentChannelGroup"];
            }
            set
            {
                ViewState["currentChannelGroup"] = value;
            }
        }

        /// <summary>
        /// Gets or sets the current channel details ID.
        /// </summary>
        /// <value>The current channel details ID.</value>
        int CurrentChannelDetailsID
        {
            get
            {
                if (ViewState["currentChannelDetailsID"] == null)
                    ViewState["currentChannelDetailsID"] = 0;

                return (int)ViewState["currentChannelDetailsID"];
            }
            set
            {
                ViewState["currentChannelDetailsID"] = value;
            }
        }

        /// <summary>
        /// Gets or sets the current search term.
        /// </summary>
        /// <value>The current search term.</value>
        string CurrentSearchTerm
        {
            get
            {
                if (ViewState["currentSearchTerm"] == null)
                    ViewState["currentSearchTerm"] = "";

                return (string)ViewState["currentSearchTerm"];
            }
            set
            {
                ViewState["currentSearchTerm"] = value;
            }
        }
        #endregion
    }
}
